/**
  data-source.c - Created by Timothy Morey on 7/3/2012.
*/

#include <libxml/tree.h>
#include <string.h>

#ifdef __WINDOWS__
#pragma warning(disable:4996)
#endif

#include "data-source.h"
#include "err.h"
#include "nvn-data-source.h"
#include "opendap-data-source.h"

/*****************************************************************************
 * Local definitions
 *****************************************************************************/

/**
  @note This is not a thread-safe implementation.  If two threads try to create
  data sources at the same time, we may end up putting them both into the same
  position, thus overwriting one.
*/
static DataSource* g_DataSources[MAX_DATA_SOURCES];


/*****************************************************************************
 * Implementation of data-source.h functions
 *****************************************************************************/

int DataSourceGetDatasetSchema(DataSourceDescriptor desc,
                               DataSetSchema* schema)
{
  int retval = NVN_NOERR;

  if(schema)
  {
    switch(desc.Type)
    {
    case DataSourceTypeLocalFile:
      retval = NVN_ENOTIMPL;
      break;
    case DataSourceTypeNvnServer:
      retval = NvnDataSourceGetDatasetSchema(desc, schema);
      break;
    case DataSourceTypeOPeNDAP:
      retval = OPeNDAPDataSourceGetDatasetSchema(desc, schema);
      break;
    }
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int DataSourceGetGridSchema(DataSourceDescriptor desc,
                            DataGridSchema* schema)
{
  int retval = NVN_NOERR;

  if(schema)
  {
    switch(desc.Type)
    {
    case DataSourceTypeLocalFile:
      retval = NVN_ENOTIMPL;
      break;
    case DataSourceTypeNvnServer:
      retval = NvnDataSourceGetGridSchema(desc, schema);
      break;
    case DataSourceTypeOPeNDAP:
      retval = OPeNDAPDataSourceGetGridSchema(desc, schema);
      break;
    }
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int DataSourceStartStream(DataSourceDescriptor desc,
                          DataFrameCallback callback,
                          int* dsid)
{
  int retval = NVN_NOERR;

  if(dsid)
  {
    switch(desc.Type)
    {
    case DataSourceTypeLocalFile:
      retval = NVN_ENOTIMPL;
      break;
    case DataSourceTypeNvnServer:
      retval = NvnDataSourceStartStream(desc, callback, dsid);
      break;
    case DataSourceTypeOPeNDAP:
      retval = OPeNDAPDataSourceStartStream(desc, callback, dsid);
      break;
    }
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int DisconnectDataSource(int dsid)
{
  int retval = NVN_NOERR;

  if(dsid >= 0 && dsid < MAX_DATA_SOURCES && g_DataSources[dsid])
  {
    switch(g_DataSources[dsid]->Type)
    {
    case DataSourceTypeLocalFile:
      retval = NVN_ENOTIMPL;
      break;
    case DataSourceTypeNvnServer:
      retval = NvnDataSourceDisconnect(dsid);
      break;
    case DataSourceTypeOPeNDAP:
      retval = OPeNDAPDataSourceDisconnect(dsid);
      break;
    }
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int GetRegisteredDataSource(int dsid, DataSource** datasource)
{
  int retval = NVN_NOERR;

  if(datasource && 0 <= dsid && dsid < MAX_DATA_SOURCES && g_DataSources[dsid])
  {
    *datasource = g_DataSources[dsid];
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int ParseDataSourceDescriptor(xmlNodePtr root, DataSourceDescriptor* desc)
{
  int retval = NVN_NOERR;
  xmlChar* value = 0;

  if(root && desc)
  {
    value = xmlGetProp(root, BAD_CAST "Type");
    desc->Type = (DataSourceType)atoi((char*)value);
    xmlFree(value);

    value = xmlGetProp(root, BAD_CAST "LocalPort");
    desc->LocalPort = atoi((char*)value);
    xmlFree(value);

    value = xmlGetProp(root, BAD_CAST "Dataset");
    strcpy(desc->Dataset, (char*)value);
    xmlFree(value);

    value = xmlGetProp(root, BAD_CAST "Varname");
    strcpy(desc->Varname, (char*)value);
    xmlFree(value);
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int RegisterDataSource(DataSource* datasource, int* dsid)
{
  int retval = NVN_NOERR;
  int i = 0;

  if(datasource && dsid)
  {
    *dsid = -1;

    for(i = 0; i < MAX_DATA_SOURCES; i++)
    {
      if(0 == g_DataSources[i])
      {
        g_DataSources[i] = datasource;
        *dsid = i;
        break;
      }
    }

    if(*dsid < 0)
      retval = NVN_EMAXOBJS;
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int SaveDataSourceDescriptor(DataSourceDescriptor desc, xmlNodePtr* root)
{
  int retval = NVN_NOERR;
  char temp[256];

  if(root)
  {
    if(! *root)
      *root = xmlNewNode(0, BAD_CAST "DataSourceDescriptor");

    sprintf(temp, "%d", desc.Type);
    xmlNewProp(*root, BAD_CAST "Type", BAD_CAST temp);
    
    sprintf(temp, "%d", desc.LocalPort);
    xmlNewProp(*root, BAD_CAST "LocalPort", BAD_CAST temp);

    xmlNewProp(*root, BAD_CAST "Dataset", BAD_CAST desc.Dataset);
    xmlNewProp(*root, BAD_CAST "Varname", BAD_CAST desc.Varname);
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}

int UnregisterDataSource(int dsid)
{
  int retval = NVN_NOERR;

  if(0 <= dsid < MAX_DATA_SOURCES)
  {
    g_DataSources[dsid] = 0;
  }
  else
  {
    retval = NVN_EINVARGS;
  }

  return retval;
}